﻿#include "ioQueue.h"

#include <QQueue>
#include <QVector>
#include <QMap>
#include <QWaitCondition>
#include <QMutex>
#include <QDebug>

#include <crtdbg.h>
#include <assert.h>

#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif

class ioQueuePrivate {
public:
    class Bind
    {
    public:
        MediaType mt;
        QQueue<AVPacket*> *list = new QQueue<AVPacket*>;
        int streamIndex         = -1;
        ~Bind();
    };

    QVector<Bind *> list;
    QMutex mutex;
    QWaitCondition waitCond;

    /**
     * @fn	void append(MediaType mt, int streamIndex)
     *
     * @brief	插入一个队列
     *
     * @author	戴华豪
     * @date	2015/8/2
     *
     * @param	mt				队列的媒体类型
     * @param	streamIndex     队列代表的stream在文件中的索引
     */
    void append(MediaType mt, int streamIndex) {
        Bind *tmp = new Bind;
        tmp->mt = mt;
        tmp->streamIndex = streamIndex;
        list.append(tmp);
    }
};

ioQueue::ioQueue(QObject *parent) :
    QObject(parent), d(new ioQueuePrivate)
{
}

ioQueue::~ioQueue()
{
    delete d;
}

void ioQueue::appendQueue(MediaType mt, int streamIndex)
{
    d->append(mt, streamIndex);
}

void ioQueue::enqueue(AVPacket *pkt)
{
    d->mutex.lock();
    if(pkt->stream_index > d->list.size()) {
        d->mutex.unlock();
        return;
    }
    //复制这个包
    av_dup_packet(pkt);
    AVPacket *tmp = (AVPacket*) av_malloc(sizeof(AVPacket));
    memcpy(tmp, pkt, sizeof(AVPacket));
    d->list[pkt->stream_index]->list->enqueue(tmp);
    d->mutex.unlock();
}

AVPacket *ioQueue::popup(int streamIndex)
{
    AVPacket *pkt = NULL;
    d->mutex.lock();
    if (streamIndex > d->list.size() || streamIndex < 0){
        d->mutex.unlock();
        return NULL;
    }
    if (d->list[streamIndex]->list->isEmpty()) {
        d->waitCond.wait(&d->mutex, 150);
    }
    if (!d->list[streamIndex]->list->isEmpty()) {
        pkt = d->list[streamIndex]->list->dequeue();
    }

    d->mutex.unlock();

    return pkt;
}

void ioQueue::clear()
{
    d->waitCond.wakeAll();
    d->mutex.lock();
    ioQueuePrivate::Bind* tmp = NULL;
    for (int i = 0; i < d->list.size(); i++) {
        if(NULL != (tmp = d->list.at(i)))
            delete tmp;
    }
    d->list.clear();
    d->mutex.unlock();
}

ioQueuePrivate::Bind::~Bind() {
    AVPacket *tmp = NULL;
    qDebug()<<list->size();
    while (!list->isEmpty()) {
        if (NULL != (tmp = list->dequeue())) {
            av_free_packet(tmp);
            av_freep(tmp);
        }
    }
    delete list;
}
